/*
 *  C++设计模式之组合模式(Composite  Pattern) 又叫部分整体模式
 * 用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象，用来表示部分以及整体层次。
 * 这种类型的设计模式属于结构型模式，它创建了对象组的树形结构。
 * 这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
*/

/*
 * 意图：将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
 *
 * 主要解决：它在我们树型结构的问题中，模糊了简单元素和复杂元素的概念，客户程序可以像处理简单元素一样来处理复杂元素，从而使得客户程序与复杂元素的内部结构解耦。
 *
 * 何时使用： 1、您想表示对象的部分-整体层次结构（树形结构）。 2、您希望用户忽略组合对象与单个对象的不同，用户将统一地使用组合结构中的所有对象。
 *
 * 如何解决：树枝和叶子实现统一接口，树枝内部组合该接口。
 *
 * 关键代码：树枝内部组合该接口，并且含有内部属性 List，里面放 Component。
 *
 * 应用实例： 1、算术表达式包括操作数、操作符和另一个操作数，其中，另一个操作符也可以是操作数、操作符和另一个操作数。 2、在 JAVA AWT 和 SWING 中，对于 Button 和 Checkbox 是树叶，Container 是树枝。
 *
 * 优点： 1、高层模块调用简单。 2、节点自由增加。
 *
 * 缺点：在使用组合模式时，其叶子和树枝的声明都是实现类，而不是接口，违反了依赖倒置原则。
 *
 * 使用场景：部分、整体场景，如树形菜单，文件、文件夹的管理。
 *
 * 注意事项：定义时为具体类。
*/

#include <list>
#include <string>
#include <memory>

#include <sstream>
#include <iostream>

/// 雇员
class Employee {

public:
    Employee(const std::string &_name, const std::string &_dept, int _sal) {
        m_name = _name;
        m_dept = _dept;
        m_salary = _sal;
    }

    ~Employee() = default;

    void add(std::shared_ptr<Employee> e) {
        m_subordinates.push_back(e);
    }

    void remove(std::shared_ptr<Employee> e) {
        m_subordinates.remove(e);
    }

    std::list<std::shared_ptr<Employee>> getSubordinates() {
        return m_subordinates;
    }

    std::string toString() {
        std::stringstream ss;
        ss << "\nEmployee: [ \nname: " << m_name << "\ndept: " << m_dept << "\nsalary: " << m_salary << "\n]";
        return ss.str();
    }

    void showAll() {
        std::cout << this->toString() << std::endl;
        for (const auto &spEmployee: m_subordinates) {
            spEmployee->showAll();
        }
    }

private:
    std::string m_name;               /// 姓名
    std::string m_dept;               /// 部门
    int m_salary;             /// 薪水
    std::list<std::shared_ptr<Employee>> m_subordinates;  /// 手底下有多少人
};


int main() {
    auto CEO = std::make_shared<Employee>(Employee("John", "CEO", 30000));
    auto headSales = std::make_shared<Employee>(Employee("Robert", "Head Sales", 20000));
    auto headMarketing = std::make_shared<Employee>(Employee("Michel", "Head Marketing", 20000));
    auto clerk1 = std::make_shared<Employee>(Employee("Laura", "Marketing", 10000));
    auto clerk2 = std::make_shared<Employee>(Employee("Bob", "Marketing", 10000));
    auto salesExecutive1 = std::make_shared<Employee>(Employee("Richard", "Sales", 10000));
    auto salesExecutive2 = std::make_shared<Employee>(Employee("Rob", "Sales", 10000));

    CEO->add(headSales);
    CEO->add(headMarketing);

    headSales->add(salesExecutive1);
    headSales->add(salesExecutive2);

    headMarketing->add(clerk1);
    headMarketing->add(clerk2);

    CEO->showAll();

    return 0;
}



